/*
"JSFXGEN" - Editor.as
Modular Integrated Development Environment for JesuSonic
Project page: http://jsfxgen.googlecode.com

Copyright 2009 Lubomir I. Ivanov

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package neolit123.jsfxgen
{
  // =========================================================
  // [ import
  // =========================================================
  import flash.display.Sprite;
  import flash.text.TextField;
  import flash.text.TextFieldType;
  import flash.text.TextFormat;
  import flash.text.TextFormatAlign;
  import flash.utils.Timer;
  import flash.events.Event;
  import flash.events.MouseEvent;  
  import flash.events.TimerEvent;
  import neolit123.ui.Box;
  import neolit123.ui.UIButton;
  import neolit123.ui.UIScrollScriptAreaV;
  import ro.victordramba.scriptarea.ScriptAreaEvents;
  import flash.filesystem.File;
  import flash.filesystem.FileMode;
  import flash.filesystem.FileStream;
  import flash.desktop.NativeApplication;
  import flash.system.Capabilities;
  // =========================================================
  // [ class
  // =========================================================
  public class Editor extends Sprite
  {  
    // @ objects
    private var bkg:Box;
    private var btn0:UIButton;
    private var btn:UIButton;
    private var vscr:UIScrollScriptAreaV;
    //private var hscr:UIScrollBar;
    private var controls:Sprite = new Sprite;
    private var code_txt:ScriptAreaEvents = new ScriptAreaEvents;
    private var line_txt:TextField = new TextField;
    private var id_txt:TextField = new TextField;
    private var label_txt:TextField = new TextField;
    private var saved_txt:TextField = new TextField;
    private var df:Function = Main.debug.df;
    private var stimer:Timer = new Timer(1000, 1);
    // @ properties
    private var btnwidth:Number;
    private var font:String = "_typewriter";
    private var fsize:Number = 14;
    private var lastnl:int = 0;
    private var result:Object;
    private var shlocal:Number;
    private var initcode:String;
    private var editid:int;    
    private var editmodule:Boolean;
    private var ext:String;
    // @ text formats
    private var tf:TextFormat = new TextFormat("_sans", 11);
    private var info_tf:TextFormat = new TextFormat("_sans", 12);
    private var line_tf:TextFormat = new TextFormat(font,fsize,0xffffff);
    private var default_tf:TextFormat = new TextFormat(font,fsize,0x000000);
    private var functions_tf:TextFormat = new TextFormat(font,fsize,0xaa0000);
    private var sysvars_tf:TextFormat = new TextFormat(font,fsize,0x0000ff);    
    private var comments_tf:TextFormat = new TextFormat(font,fsize,0x009900);
    // @ search strings
    //private var chars_str:String = "\\$|\\'|\\s|\\n|\\t|\\{|\\[|\\(|\\}|\\]|\\)|\\+|\\-|\\<|\\>|\\?|\\/|\\=|\\;|\\:|\\*|\\^|\\%|\\!|\\&|\\.";
    private var functions_str:String = "gfx_lineto|gfx_rectto|gfx_setpixel|gfx_getpixel|gfx_drawnumber|gfx_drawchar|gfx_blurto|gfx_blit|gfx_blitext|gfx_getimgdim|sin|cos|tan|asin|acos|atan|atan2|sqr|sqrt|pow|exp|log|log10|abs|min|max|sign|rand|floor|ceil|invsqrt|spl|loop|while|mdct|fft|ifft|fft_permute|fft_ipermute|convolve_c|freembuf|memcpy|memset|sliderchange|file_open|file_close|file_rewind|file_var|file_mem|file_avail|file_riff|midisend|midirecv";  
    private var sysvars_str:String = "pi|e|sample|block|gfx|serialize|slider|init|desc|filename|srate|num_ch|samplesblock|tempo|play_state|play_position|beat_position|ext_noinit|reg|pdc_delay|pdc_bot_ch|pdc_top_ch|pdc_midi|gfx_r|gfx_g|gfx_b|gfx_a|gfx_w|gfx_h|gfx_x|gfx_y|gfx_mode|gfx_clear|gfx_texth|mouse_x|mouse_y|mouse_cap";
    // @ regular expressions    
    private var functions_re:RegExp = new RegExp("(\\b)("+functions_str+"){1}(\\b)","g");
    private var sysvars_re:RegExp = new RegExp("(\\b|\\@|\\$)("+sysvars_str+"){1}(\\b)","g");
    private var comments_re:RegExp = new RegExp("//.*","g");
    // =========================================================
    // [ constructor
    // =========================================================
    public function Editor():void
    {
      // ------------------------
      // [ add bkg
      // ------------------------
      bkg = new Box(Main.sw,Main.sh,Main.bkgcolor,Main.bkgcolor);
      addChild(bkg);
      bkg.buttonMode = true;
      bkg.mouseChildren = false;
      bkg.useHandCursor = false;
      // ------------------------
      // [ add line text
      // ------------------------
      //addChild(line_txt);
      line_tf.align = "right";
      with (line_txt) 
      {
        defaultTextFormat = line_tf;
        width = 50;
        background = true;
        backgroundColor = 0x444444;
        textColor = 0xffffff;
        mouseEnabled = false;
        multiline = true;
      }
      // ------------------------
      // [ add code text
      // ------------------------
      addChild(code_txt);
      //code_txt.x = line_txt.width;
      code_txt.x = 0;
      // ------------------------
      // [ add scrollbars
      // ------------------------
      vscr = new UIScrollScriptAreaV(code_txt);
      addChild(vscr);
      // ------------------------
      // [ add controls
      // ------------------------
      addChild(controls);
      // @ btn save
      btn0 = new UIButton();
      controls.addChild(btn0);
      var btnx:Number = 10;
      btnwidth = 70;
      btn0.setsize(btnwidth,null);
      btn0.x = btnx;
      btn0.setlabel("Save");
      // @ btn export
      btn = new UIButton();
      controls.addChild(btn);
      btn.setsize(btnwidth,null);
      btnx += btnwidth+5;
      btn.x = btnx;
      btn.setlabel("Export");
      btn.addEventListener(MouseEvent.CLICK, export_f);
      function export_f(e:MouseEvent=null):void {
      var ffstr0:String;
        if (editmodule) {
          ext = ".jsmod";
          ffstr0 = "JSfxGen module (*.jsmod)";
        } else {
          ext = ".jsfx";
          ffstr0 = "JesuSonic code (Suggested extention *.jsfx)";
        }
        var file:File;
        if (Main._os == "win")
          file = File.applicationDirectory.resolvePath('modules/*'+ext);
        else
          file = File.applicationStorageDirectory.resolvePath('modules/*'+ext);
        file.addEventListener(Event.SELECT, doexport);
        file.browseForSave("Export "+ffstr0);        
      }
      // @ btn close
      btn = new UIButton();
      controls.addChild(btn);
      btn.setsize(btnwidth,null);
      btnx += btnwidth+5;
      btn.x = btnx;
      btn.setlabel("Close");
      btn.addEventListener(MouseEvent.CLICK, close_f);
      function close_f(e:MouseEvent=null):void {
        if (initcode.length == code_txt.text.length) {
          editorclose();
        } else {
          Main.dialog.update("Close editor? Unsaved text will be lost!" , "Yes", "Cancel", editorclose, Main.dialog.close);
        }
      }
      // @ btn highlight
      btn = new UIButton();
      controls.addChild(btn);
      btn.setsize(btnwidth,null);
      btnx += btnwidth+5;
      btn.x = btnx;
      btn.setlabel("---");
      btn.addEventListener(MouseEvent.CLICK, hl_f);
      function hl_f(e:MouseEvent=null):void {
        //highlight(-1);
      }
      btn.setsize(btnwidth,null);
      btnx += btnwidth+10;
      // @ add id txt
      controls.addChild(id_txt);
      with (id_txt) {
        x = btnx;
        y = 5;
        width = 30;
        height = 20;
        tf.align = "center";
        defaultTextFormat = tf;
        background = true;
        backgroundColor = 0xffffff;
        textColor = 0x000000;
        selectable = false;
      }
      // @ add label txt
      controls.addChild(label_txt);
      with (label_txt) {
        x = id_txt.x + id_txt.width + 5;
        y = 5;
        width = 200;
        height = 20;
        tf.align = "left";
        tf.leftMargin = 5; 
        defaultTextFormat = tf;
        background = true;
        backgroundColor = 0xffffff;
        textColor = 0x000000;
        selectable = true;
        type = "input";
        maxChars = 30;
      }
      // @ saved txt
      controls.addChild(saved_txt);
      with (saved_txt) {
        x = label_txt.x + label_txt.width + 5;
        y = 5;
        width = 100;
        height = 20;
        defaultTextFormat = tf;
        textColor = 0xffffff;
        selectable = false;
        text = "Saved";
        visible = false;
      }
      // @ hide on init
      visible = false;
    }
    // =========================================================
    // [ align editor to stage
    // =========================================================
    public function align(sw:Number,sh:Number):void
    {
      bkg.width = sw;
      bkg.height = shlocal = sh;
      code_txt.height = line_txt.height = sh-btn.height-controls.height+10;
      code_txt.width = sw - 15;
      controls.y = code_txt.height+10;
      vscr.update();
    }
    // =========================================================
    // [ open editor for module
    // =========================================================
    public function open(id:int,lb:String,moddata:String,em:Boolean):void
    {
      // @ set save 
      btn0.setlabel("Save");
      btn0.addEventListener(MouseEvent.CLICK, save_f);
      // @ reset undo and selection
      code_txt.resetUndo();
      code_txt.setSelection(0,0);
      // @ hide bkg stuff for speed up?
      Main.mc.visible = Main.lines.visible = false;
      // @ update text, ids, labels
      editid = id;
      editmodule = em;
      label_txt.text = lb;
      id_txt.text = id.toString();
      code_txt.text = moddata;
      initcode = code_txt.text;
      // @ update scroll
      vscr.update(); 
      // @ unhide
      visible = true;
      
      // @ highlight stuff
      /*
      code_txt.addFormatRun(0, 10, false, false, 'ff0000');
      code_txt.applyFormatRuns();
      */      
    }
    // =========================================================
    // [ open editor for generated js
    // =========================================================
    public function openjs(str:String):void
    {
      df("EDITOR Open generated code");
      editmodule = false;
      // @ set save
      btn0.setlabel("---");
      btn0.removeEventListener(MouseEvent.CLICK, save_f);
      // @ reset undo and selection
      code_txt.resetUndo();
      code_txt.setSelection(0,0);
      // @ hide bkg stuff for speed up?
      Main.mc.visible = Main.lines.visible = false;
      // @ update text and labels
      label_txt.text = "Generated code";
      id_txt.text = "-";
      code_txt.text = str;
      initcode = code_txt.text;
      // @ unhide
      visible = true;
    }
    // =========================================================
    // [ editor close
    // =========================================================
    public function editorclose():void
    {
      df("EDIT Close [ "+editid+" ]");
      // @ clear history & close
      visible = false;
      Main.mc.visible = Main.lines.visible = true;
      Main.dialog.close();
    }
    // =========================================================
    // [ export
    // =========================================================
    private function doexport(event:Event):void
    {
      // @ do export
      df("EXPORT begin");     
      
      var directory:String;
      var file:File;
      
      var savefile:File = File(event.target);
      directory = savefile.url;
      
      if (Main._os == "win")
      {
        if(directory.indexOf(ext) == -1) directory += ext;
        file = new File();
        file = file.resolvePath(directory);
      } 
      else
      {
        df("here");
        directory = directory.substr(directory.lastIndexOf("/")+1, directory.length);
        if(directory.indexOf(ext) == -1) directory += ext;
        df(directory);
        file = File.applicationStorageDirectory;       
        file = file.resolvePath("modules/"+directory);
      }
      
      var fs:FileStream = new FileStream();
      fs.open(file, FileMode.WRITE);
      fs.writeUTFBytes(code_txt.text.split("\r").join("\n"));
      fs.close();
      // @ notification text
      saved_txt.text = "Exported";
      saved_txt.visible = true;
      // @ call timeout
      stimer.start();
      stimer.addEventListener(TimerEvent.TIMER, hidesaved);
      df("EXPORTED Module [ "+editid+" ] to " + directory);      
    }    
    // =========================================================
    // [ save
    // =========================================================
    private function save_f(e:MouseEvent=null):void
    {
      // @ update properties
      df("SAVE Module [ "+editid+" ]");
      Main.m_ar[editid].lb = label_txt.text;
      Main.m_ar[editid].moddata = code_txt.text;
      Main.m_ar[editid].update();
      initcode = code_txt.text;
      // @ notification text
      saved_txt.text = "Saved";
      saved_txt.visible = true;
      // @ call timeout
      var stimer:Timer = new Timer(1000, 1);
      stimer.start();
      stimer.addEventListener(TimerEvent.TIMER, hidesaved);
    }
    // =========================================================
    // [ hide saved
    // =========================================================
    private function hidesaved(e:TimerEvent=null):void
    {
      stimer.removeEventListener(TimerEvent.TIMER, hidesaved);
      saved_txt.visible = false;
    }    
  }
}